package com.security.door.core.dao.query;

import com.google.common.collect.Lists;
import com.security.door.core.constants.Constants;
import com.security.door.utils.collectionUtil.MapUtil;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.List;
import java.util.Map;

@Data
public class QueryParam {

    private static final Logger logger = LoggerFactory.getLogger(QueryParam.class);

    private List<Query> queryList = Lists.newArrayList();
    private List<Order> orderList = Lists.newArrayList();
    private int pageIndex = Constants.DEFAULT_PAGE_INDEX;
    private int pageSize = Constants.DEFAULT_PAGE_SIZE;
    private boolean isForUpdate = false;
    private boolean isQueryDeleted = false;
    private boolean isCountPage = true;

    public static QueryParam create() {
        return new QueryParam();
    }

    public static QueryParam create(Integer pageIndex, Integer pageSize) {
        QueryParam queryParam = create();
        queryParam.setPageIndex(pageIndex);
        queryParam.setPageSize(pageSize);
        return queryParam;
    }

    /**
     * 把领域实体对象中的非空属性，转为QueryParam查询对象，查询条件都是=
     *
     * @param pageIndex 页码，从1开始
     * @param pageSize  每页数据条数
     * @param object    领域实体对象
     * @return QueryParam
     */
    public static QueryParam create(Integer pageIndex, Integer pageSize, Object object) {
        QueryParam queryParam = create(pageIndex, pageSize);
        return create(queryParam, object);
    }

    public static QueryParam create(Object object) {
        QueryParam queryParam = create();
        return create(queryParam, object);
    }

    private static QueryParam create(QueryParam queryParam, Object object) {
        Map<String, Object> map;
        try {
            map = MapUtil.beanToMap(object);
        } catch (Exception e) {
            logger.warn("beanToMap error", e);
            return null;
        }
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            Object value = entry.getValue();
            if (value != null) {
                queryParam.addQuery(entry.getKey(), value);
            }
        }
        return queryParam;
    }

    public void setPageSize(Integer pageSize) {
        if (pageSize != null) {
            this.pageSize = Math.min(100000, Math.max(0, pageSize));
        }
    }

    public void setPageIndex(Integer pageIndex) {
        if (pageIndex != null) {
            this.pageIndex = Math.max(1, pageIndex);
        }
    }

    public int getOffset() {
        return (pageIndex - 1) * pageSize;
    }

    public QueryParam addQuery(String key, Object value) {
        queryList.add(new Query(key, value));
        return this;
    }

    public QueryParam addQuery(String key, Query.Opt opt) {
        // value就取opt.toString()，方便toExample方法对value判空
        queryList.add(new Query(key, opt, opt.toString()));
        return this;
    }

    public QueryParam addQuery(String key, Query.Opt opt, Object value) {
        queryList.add(new Query(key, opt, value));
        return this;
    }

    public QueryParam addQuerys(List<Query> queries) {
        queryList.addAll(queries);
        return this;
    }

    public QueryParam addOrder(String key) {
        orderList.add(new Order(key, Order.OrderType.desc));
        return this;
    }

    public QueryParam addOrder(String key, Order.OrderType orderType) {
        orderList.add(new Order(key, orderType));
        return this;
    }

    public boolean isQueryEmpty() {
        List<Query> queryList = this.getQueryList();
        if (CollectionUtils.isEmpty(queryList)) {
            return true;
        }
        for (Query query : queryList) {
            if (!CollectionUtils.isEmpty(query.getValue())) {
                return false;
            }
        }
        return true;
    }

    public Example toExample(Class<?> entityClass) {
        Example example = new Example(entityClass);
        Example.Criteria criteria = example.createCriteria();
        // 组装查询条件
        for (Query query : this.getQueryList()) {
            if (CollectionUtils.isEmpty(query.getValue())) {
                continue;
            }
            if (query.getOpt().equals(Query.Opt.in.toString())) {
                criteria.andIn(query.getKey(), query.getValue());
            } else if (query.getOpt().equals(Query.Opt.notIn.toString())) {
                criteria.andNotIn(query.getKey(), query.getValue());
            } else {
                Object value = query.getValue().get(0);
                if (value instanceof String) {
                    String trim = StringUtils.trim(String.valueOf(value));
                    if (StringUtils.isEmpty(trim)) {
                        continue;
                    }
                    value = trim;
                }
                if (value != null && value != "") {
                    if (query.getOpt().equals(Query.Opt.eq.toString())) {
                        criteria.andEqualTo(query.getKey(), value);
                    } else if (query.getOpt().equals(Query.Opt.gt.toString())) {
                        criteria.andGreaterThan(query.getKey(), value);
                    } else if (query.getOpt().equals(Query.Opt.lt.toString())) {
                        criteria.andLessThan(query.getKey(), value);
                    } else if (query.getOpt().equals(Query.Opt.gte.toString())) {
                        criteria.andGreaterThanOrEqualTo(query.getKey(), value);
                    } else if (query.getOpt().equals(Query.Opt.lte.toString())) {
                        criteria.andLessThanOrEqualTo(query.getKey(), value);
                    } else if (query.getOpt().equals(Query.Opt.nq.toString())) {
                        criteria.andNotEqualTo(query.getKey(), value);
                    } else if (query.getOpt().equals(Query.Opt.like.toString())) {
                        criteria.andLike(query.getKey(), "%" + value.toString() + "%");
                    } else if (query.getOpt().equals(Query.Opt.lLike.toString())) {
                        criteria.andLike(query.getKey(), value.toString() + "%");
                    } else if (query.getOpt().equals(Query.Opt.isNull.toString())) {
                        criteria.andIsNull(query.getKey());
                    } else if (query.getOpt().equals(Query.Opt.isNotNull.toString())) {
                        criteria.andIsNotNull(query.getKey());
                    }
                }
            }
        }

        // 组装排序条件
        for (Order order : this.getOrderList()) {
            if (StringUtils.isEmpty(order.getKey())) {
                continue;
            }
            Example.OrderBy orderBy = example.orderBy(order.getKey());
            if (order.getOrderType().equals(Order.OrderType.desc)) {
                orderBy.desc();
            } else {
                orderBy.asc();
            }
        }

        if (isForUpdate) {
            example.setForUpdate(true);
        }
        return example;
    }

}